package binder

import "mi/compiler/ast"

type Symbol struct {
	Count            int
	Flags            SymbolFlags       // Symbol Flags
	Name             string            // PkgName of Symbol
	ID               int               // Unique ID (used to look up SymbolLinks)
	Declarations     []ast.Declaration // Decls associated with this Symbol
	Parent           *Symbol           // Parent Symbol
	Members          *SymbolTable      // Class, interface or literal instance members
	Exports          *SymbolTable      // Module exports
	ValueDeclaration ast.Declaration   // First value declaration of the Symbol

	/* internal */
	IsReferenced bool // True if the symbol is referenced elsewhere
}

func NewSymbol() *Symbol {
	return new(Symbol)
}

type SymbolFlags int

const (
	None                   SymbolFlags = 0
	FunctionScopedVariable SymbolFlags = 1 << iota // Parameter
	BlockScopedVariable                            // Variable
	Package                                        // Package
	Field                                          // Field or enum member
	EnumMember                                     // Enum member
	Function                                       // Function
	Class                                          // Class
	AnonymousClass                                 // Anonymous class
	Interface                                      // Interface
	Enum                                           // Enum
	Annotation                                     // Annotation
	Method                                         // Method
	Missing                                        // Missing symbol
	Constructor                                    // Constructor
	Signature                                      // Call construct or index signature
	TypeParameter                                  // Type parameter
	Transient                                      // Transient symbol (created during type check)
	Duplicate                                      // Container exclude flags
	TypeAlias                                      // Type Alias (class or interface)
	FieldAlias                                     // Class or interface Field
	MethodAlias                                    // Class or interface Method

	AliasLike    		= FieldAlias | TypeAlias | MethodAlias
	FieldLike     		= Field | FieldAlias | EnumMember
	MethodLike    		= Method | MethodAlias
	ClassLike     		= Class | Enum | AnonymousClass
	InterfaceLike 		= Interface | Annotation
	ClassOrInterface 	= ClassLike|InterfaceLike
	Variable      		= FunctionScopedVariable | BlockScopedVariable
	Value         		= Variable | Field | EnumMember | Class | Enum | AnonymousClass | Interface | Annotation | TypeAlias | FieldAlias
	Type          		= Class | AnonymousClass | Interface | Enum | EnumMember | Annotation | Annotation | TypeParameter | TypeAlias
	Namespace     		= Class | Interface | Enum | Annotation | Package

	// Block-scoped declarations are not allowed to be re-declared
	// they can not merge with anything in the value space
	BlockScopedVariableExcludes = Value

	ParameterExcludes     = Value
	FieldExcludes         = Value & ^FieldAlias
	FieldAliasExcludes    = Value
	EnumMemberExcludes    = Value
	ClassExcludes         = Type & ^TypeAlias
	TypeAliasExcludes     = Type
	InterfaceExcludes     = Type
	AnnotationExcludes    = Type
	EnumExcludes          = Type
	MethodExcludes        = None
	MethodAliasExcludes   = Method
	TypeParameterExcludes = Type & ^TypeParameter

	Merge = Method | MethodAlias | Constructor
	Call  = Method | Function | MethodAlias

	HasExports = Class | Enum | Interface | Annotation | AnonymousClass | Package
	HasMembers = Class | Enum | Interface | Annotation | AnonymousClass

	ClassMember = Method | Field

	/* @internal */
	// The set of things we consider semantically classifiable.  Used to speed up the LS during
	// classification.
	Classifiable = Class | Enum | Interface | TypeParameter
)

